package wykop.download;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;

import org.apache.log4j.Logger;
import org.w3c.dom.Node;

import wykop.download.proxy.IProxyProvider;
import wykop.download.proxy.ProxyProvider;
import wykop.utils.Streams;
import wykop.utils.XmlUtils;

class Response {

	private final int responseCode;
	private final InputStream stream;

	public Response(final int responseCode, final InputStream stream) {
		super();
		this.responseCode = responseCode;
		this.stream = stream;
	}

	public int getResponseCode() {
		return responseCode;
	}

	public InputStream getStream() {
		return stream;
	}
}

/**
 * Capable of downloading a page.
 * 
 * @author kad
 * 
 */
public class WykopDownloader {

	private static final Logger logger = Logger.getLogger("wykop.download");
	private static final IProxyProvider proxyProvider = ProxyProvider
			.getInstance();

	public static Node get(final int number) throws DownloadingPageFailed,
			DownloadingPageFailedWith404 {

		int code = -2;

		try {
			logger.debug("Downloading page " + number);
			final Response response = open(number);
			code = response.getResponseCode();
			if (code == HttpURLConnection.HTTP_OK) {
				return XmlUtils.fromHtmlStream(response.getStream());
			}
		} catch (final Exception ex) {
			logger.warn("Downloading page " + number + " failed", ex);
			throw new DownloadingPageFailed(ex);
		}

		if (code == HttpURLConnection.HTTP_NOT_FOUND) {
			throw new DownloadingPageFailedWith404("Page " + number
					+ " does not exists");
		}

		throw new DownloadingPageFailedWith404("Downloading page " + number
				+ " failed with unknown reason");

	}

	private static Response open(final int number) throws IOException {

		final Proxy proxy = proxyProvider.getProxy();
		final URL url = new URL("http://www.wykop.pl/link/" + number);
		// URL url = new
		// URL("http://ukryjsie.pl/browse.php?u=http%3A%2F%2Fwww.wykop.pl%2Flink%2F"
		// + number + "&b=1");
		final HttpURLConnection connection = (HttpURLConnection) url
				.openConnection(proxy);
		connection.setRequestMethod("GET");
		connection.setReadTimeout(100000);
		connection.connect();
		final int status = connection.getResponseCode();

		if (status == HttpURLConnection.HTTP_OK) {
			final byte[] bytes = Streams.readFully(connection.getInputStream());
			final Response response = new Response(status,
					new ByteArrayInputStream(bytes));
			return response;
		}
		if (status == HttpURLConnection.HTTP_NOT_FOUND) {
			return new Response(status, null);
		}
		throw new ConnectException("Page " + number + " failed with code "
				+ status);
	}

	static private InputStream readFully(final InputStream is)
			throws IOException {

		final ByteArrayOutputStream buffer = new ByteArrayOutputStream();

		int nRead;
		final byte[] data = new byte[16384];

		while ((nRead = is.read(data, 0, data.length)) != -1) {
			buffer.write(data, 0, nRead);
		}

		try {
			buffer.flush();
		} catch (final IOException e) {
			throw new RuntimeException();
		}

		if (buffer.toByteArray().length < 16384 * 3) {
			return null;
		}

		return new ByteArrayInputStream(buffer.toByteArray());
	}
}
